import moment from 'moment';
import crypto from 'crypto';
import https from 'https';
import urltil from 'url';
import validator from 'validator';
import config from './config';
import log from '../../log';
//import accessTokenJson from './access_token'; //引入本地存储的 access_token
import {buildLoginToken} from '../../api/sys/user/core';
import * as userData from '../../api/sys/user/data';
import * as utils from '../../util';
import * as redis from '../../redis';
import * as dict from '../../api/dict';


/**
 * 用于处理 https Get请求方法
 * @param {String} url 请求地址
 */
function httpsRequestGet(url) {
    log.info('wx httpsRequestGet url:', url);
    return new Promise((resolve, reject) => {
        https.get(url, (res) => {
            const buffer = [];
            let result = '';
            //监听 data 事件
            res.on('data', (data) => {
                buffer.push(data);
            });
            //监听 数据传输完成事件
            res.on('end', () => {
                result = Buffer.concat(buffer).toString('utf-8');
                //将最后结果返回
                resolve(result);
            });
        }).on('error', (err) => {
            log.error('httpsRequestGet url:', url);
            log.error('httpsRequestGet error:', err);
            reject(err);
        });
    });
}

/**
 * 用于处理 https Post请求方法
 * @param {String} url  请求地址
 * @param {JSON} data 提交的数据
 */
function httpsRequestPost(url, data) {
    return new Promise((resolve, reject) => {
        //解析 url 地址
        const urlData = urltil.parse(url);
        //设置 https.request  options 传入的参数对象
        const options = {
            //目标主机地址
            hostname: urlData.hostname,
            //目标地址
            path: urlData.path,
            //请求方法
            method: 'POST',
            //头部协议
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded',
                'Content-Length': Buffer.byteLength(data, 'utf-8')
            }
        };
        const req = https.request(options, (res) => {
            const buffer = [];
            let result = '';
            //用于监听 data 事件 接收数据
            res.on('data', (data) => {
                buffer.push(data);
            });
            //用于监听 end 事件 完成数据的接收
            res.on('end', () => {
                result = Buffer.concat(buffer).toString('utf-8');
                resolve(result);
            });
        })
        //监听错误事件
            .on('error', (err) => {
                log.error('httpsRequestGet url:', url);
                log.error('httpsRequestPost error:', err);
                reject(err);
            });
        //传入数据
        req.write(data);
        req.end();
    });
}

function getCode(scope) {
    // 第一步：用户同意授权，获取code
    // 这是编码后的地址
    const returnUri = encodeURIComponent('http://api.51fugui.com/api/wx/token_bycode');
    scope = scope === 'snsapi_userinfo' ? 'snsapi_userinfo' : 'snsapi_base';
    log.info('getCode scope:', scope);
    return (`https://open.weixin.qq.com/connect/oauth2/authorize?appid=${config.appID}&redirect_uri=${returnUri}&response_type=code&scope=${scope}&state=STATE#wechat_redirect`);
}

/*//目前没有用，暂不实现
function getAccessToken() {
    // TODO:判断accessToken是否过期
    // 网页授权中通过code获取的每个用户的access_token是每个用户都不同，当需要此用户后多重操作时，就需要保存到后台数据库中，通过刷新access_token来延续有效期
    // 同时刷新延续的最大有效时长是一个月，调用刷新延续有效期失败时，再调用重新获取接口
    const url1 = `https://api.weixin.qq.com/sns/oauth2/access_token?appid=${config.appID}&secret=${config.appScrect}&code=${code}&grant_type=authorization_code`;
    return httpsRequestGet(url1).then((data1) => {
        log.info('getAuthAccessToken return:', data1);
        // 第三步：拉取用户信息(需scope为 snsapi_userinfo)
        //console.log(JSON.parse(body));
        data1 = JSON.parse(data1);
        accessTokenJson.access_token = data1.access_token;
        accessTokenJson.expires_time = new Date().getTime();
    });
}*/

/*
/!**
 * 用于把用utf16编码的字符转换成实体字符，以供后台存储
 * @param  {string} str 将要转换的字符串，其中含有utf16字符将被自动检出
 * @return {string}     转换后的字符串，utf16字符将被转换成&#xxxx;形式的实体字符
 *!/
function utf16toEntities(str) {
    const patt = /[\ud800-\udbff][\udc00-\udfff]/g; // 检测utf16字符正则
    str = str.replace(patt, function (char) {
        if (char.length === 2) {
            return ';'
        } else {
            return char;
        }
    });
    return str;
}*/

function getTokenByOpenID(query, ctx) {
    // 第二步：通过code换取网页授权access_token
    const code = query.code;
    log.info('code:', code);
    //const scope = query.scope;
    if (!code) {
        return ctx.throw(500, 'code 获取失败');
    }
    /**
     * 网页授权access_token
     * 网页授权access_token 是一次性的，而基础支持的access_token的是有时间限
     */
    const url1 = `https://api.weixin.qq.com/sns/oauth2/access_token?appid=${config.appID}&secret=${config.appScrect}&code=${code}&grant_type=authorization_code`;
    return httpsRequestGet(url1).then((data1) => {
        log.info('getAuthAccessToken return:', data1);
        // 第三步：拉取用户信息(需scope为 snsapi_userinfo)
        //console.log(JSON.parse(body));
        data1 = JSON.parse(data1);
        const accessToken = data1.access_token;
        const expiresIn = data1.expires_in;
        const openid = data1.openid;
        log.info('getTokenByOpenID httpsRequestGet accessToken:', accessToken);
        log.info('openid:', openid);
        let scope = '';
        return redis.getUserWeiXinScope({openid}).then(r => {
            scope = r;
            log.info('scope:', scope);
            if (!openid) {
                return ctx.throw(500, 'openid 获取失败');
            }
            //根据openId判断是否在数据库中有用户
            return userData.getUser([{openId: openid}], 0).then(res => {
                const user = res ? res.toJSON()[0] : undefined;
                if (!user) {
                    //不存在就用scope=snsapi_userinfo再获取一遍
                    //返回scope=snsapi_userinfo获取code调用url
                    if (scope !== 'snsapi_userinfo') {
                        //TODO:存储到redis中scope值
                        redis.setUserWeiXinScope({openid, scope: 'snsapi_userinfo'});
                        return {url: getCode('snsapi_userinfo')};
                    }
                    const url2 = `https://api.weixin.qq.com/sns/userinfo?access_token=${accessToken}&openid=${openid}&lang=zh_CN`;
                    return httpsRequestGet(url2).then((data) => {
                        // 第四步：根据获取的用户信息进行对应操作
                        const wxUserinfo = JSON.parse(data);
                        log.info('wxUserinfo:', wxUserinfo);
                        //判断用户信息是否获取成功
                        if (data.errcode > 0) {
                            log.error('微信授权获取用户基本信息失败:', wxUserinfo);
                            throw data;
                        }
                        //throw '用户不存在';
                        //注册用户
                        const addUserInfo = {
                            id: utils.uuid(),
                            username: `wx_${moment().format('YYYYMMDD')}${utils.randomDigits(4)}`,
                            name: validator.isSurrogatePair(wxUserinfo.nickname) ? '' : wxUserinfo.nickname,
                            avatar: wxUserinfo.headimgurl,
                            userType: dict.UserType.wx,
                            password: 'nopassword',
                            openId: wxUserinfo.openid,
                            status: '1',
                            gender: wxUserinfo.sex, // 用户的性别，值为1时是男性，值为2时是女性，值为0时是未知
                            unionid: wxUserinfo.unionid,
                            access_token: accessToken,
                            expires_time: new Date().getTime() + expiresIn,
                        };
                        log.info('addUserInfo:', addUserInfo);
                        return userData.add(addUserInfo).then(() => {
                            return buildLoginToken(addUserInfo);
                        });
                    });
                }
                //存在就直接返回系统登录token
                log.info('user:', user);
                if (user.status !== '1') {
                    //throw '用户未启用';
                    return ctx.throw(500, '用户未启用');
                }
                log.info('log result is1 =----', JSON.stringify(user));
                return buildLoginToken(user);
            });
        });
    });
}

/**
 * 微信接入验证
 * @param query
 */
function auth(query) {
//1.获取微信服务器Get请求的参数 signature、timestamp、nonce、echostr
    const signature = query.signaturer;//微信加密签名
    const timestamp = query.timestampr;//时间戳
    const nonce = query.noncer;//随机数
    const echostr = query.echostr;//随机字符串

    //2.将token、timestamp、nonce三个参数进行字典序排序
    const array = [config.token, timestamp, nonce];
    array.sort();

    //3.将三个参数字符串拼接成一个字符串进行sha1加密
    const tempStr = array.join('');
    const hashCode = crypto.createHash('sha1'); //创建加密类型
    const resultCode = hashCode.update(tempStr, 'utf8').digest('hex'); //对传入的字符串进行加密

    //4.开发者获得加密后的字符串可与signature对比，标识该请求来源于微信
    if (resultCode === signature) {
        return echostr;
    }
    return 'mismatch';
}

function MP() {
    return new Promise((resolve) => {
        resolve('tdBVXQ6ZL2Qc5K2R');
    });
}

export {auth, httpsRequestGet, httpsRequestPost, getCode, getTokenByOpenID, MP};
